home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / gtetris / playing.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  10KB  |  427 lines

  1. /*
  2. # GENERIC X-WINDOW-BASED TETRIS
  3. #
  4. #    playing.c
  5. #
  6. ###
  7. #
  8. #  Copyright (C) 1992, 1993     Qiang Alex Zhao, azhao@cs.arizona.edu
  9. #        Computer Science Dept, University of Arizona
  10. #
  11. #            All Rights Reserved
  12. #
  13. #  Permission to use, copy, modify, and distribute this software and
  14. #  its documentation for any purpose and without fee is hereby granted,
  15. #  provided that the above copyright notice appear in all copies and
  16. #  that both that copyright notice and this permission notice appear in
  17. #  supporting documentation, and that the name of the author not be
  18. #  used in advertising or publicity pertaining to distribution of the
  19. #  software without specific, written prior permission.
  20. #
  21. #  This program is distributed in the hope that it will be "playable",
  22. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  24. #
  25. */
  26.  
  27. #include    "tetris.h"
  28.  
  29. static Bool     paused = False;
  30. static Bool     firstFall = False;
  31.  
  32. static int      speeds[NUM_LEVELS] = {
  33. 100, 92, 84, 76, 68, 60, 53, 46, 39, 32, 26, 20, 15, 10, 6, 3, 1, 0};
  34. static int      thresh[NUM_LEVELS] = {
  35.     10, 20, 30, 40, 50, 60, 70, 80, 90,
  36. 100, 110, 120, 130, 140, 150, 160, 170, 180};
  37.  
  38. static struct timeval nextFall, now, delay;
  39. static struct timezone tzone = {0, 0};
  40.  
  41. /* ------------------------------------------------------------------ */
  42.  
  43. void
  44. playing()
  45. {
  46.     Bool            resetTime = True;
  47.     int             conNum = ConnectionNumber(display);
  48.  
  49.     score = prefilled * level * 10;
  50.     while (True) {
  51.     if (resetTime) {
  52.         (void) gettimeofday(&nextFall, &tzone);
  53.         nextFall.tv_usec += 10000 * speeds[level];
  54.         realTime(&nextFall);
  55.     } else {
  56.         int             writefd = 0, exceptfd = 0;
  57.         int             readfd = 1 << conNum;
  58.  
  59.         (void) gettimeofday(&now, &tzone);
  60.         delay.tv_sec = nextFall.tv_sec - now.tv_sec;
  61.         delay.tv_usec = nextFall.tv_usec - now.tv_usec;
  62.         realTime(&delay);
  63.         if (((long) delay.tv_sec > 0) ||
  64.             (((long) delay.tv_sec == 0) &&
  65.             ((long) delay.tv_usec > 0))) {
  66.         /* sleep */
  67.         (void) select(conNum + 1, (fd_set *) & readfd,
  68.                (fd_set *) & writefd, (fd_set *) & exceptfd, &delay);
  69.         }
  70.     }
  71.     (void) gettimeofday(&now, &tzone);
  72.     if ((now.tv_sec > nextFall.tv_sec) ||
  73.         ((now.tv_sec == nextFall.tv_sec) &&
  74.          (now.tv_usec > nextFall.tv_usec))) {
  75.         (void) evGotNewThing(True);
  76.         resetTime = True;
  77.         firstFall = True;
  78.     } else {
  79.         resetTime = evGotNewThing(False);
  80.     }
  81.     }
  82.     /* never come to here */
  83. }
  84.  
  85. /* ------------------------------------------------------------------ */
  86.  
  87. Bool
  88. evGotNewThing(falldown)
  89.     Bool            falldown;
  90. {
  91.     XEvent          ev;
  92.     Bool            gotNew = False, flag;
  93.     char            buf[4];
  94.  
  95.     if (!paused && falldown)
  96.     gotNew = moveOne(FALL) || gotNew;
  97.  
  98.     while (XPending(display)) {
  99.     XNextEvent(display, &ev);
  100.     flag = True;
  101.     while (flag) {
  102.         switch (ev.type) {
  103.         case KeyPress:
  104.         if (!XLookupString(&ev.xkey, buf, 4, NULL, NULL))
  105.             break;
  106.  
  107.         switch (buf[0]) {
  108.         case 'j':
  109.         case 's':
  110.             if (!paused)
  111.             gotNew = moveOne(LEFT) || gotNew;
  112.             break;
  113.  
  114.         case 'k':
  115.         case 'd':
  116.             if (!paused)
  117.             gotNew = moveOne(ROTATE) || gotNew;
  118.             break;
  119.  
  120.         case 'l':
  121.         case 'f':
  122.             if (!paused)
  123.             gotNew = moveOne(RIGHT) || gotNew;
  124.             break;
  125.  
  126.         case ' ':
  127.         case '\n':
  128.             if (!paused)
  129.             gotNew = moveOne(DROP) || gotNew;
  130.             break;
  131.  
  132.         case 'q':
  133.         case 'Q':
  134.             gameOver();
  135.             break;
  136.  
  137.         case '+':
  138.         case '=':
  139.             if (!paused)
  140.             if (level < NUM_LEVELS - 1) {
  141.                 level++;
  142.                 drawStatus();
  143.             }
  144.             break;
  145.  
  146.         case '-':
  147.         case '_':
  148.             if (!paused)
  149.             if (level > 0) {
  150.                 level--;
  151.                 drawStatus();
  152.             }
  153.             break;
  154.  
  155.         case 'b':
  156.         case 'B':
  157.             beep = !beep;
  158.             if (beep)
  159.             XBell(display, BVOLUME);
  160.             break;
  161.  
  162.         case 'p':
  163.         case 'P':
  164.             if (beep)
  165.             XBell(display, BVOLUME);
  166.             paused = !paused;
  167.             if (paused) {
  168.             /* "... Hi boss, I'm working hard as usual ..." */
  169.             banner(MSG_PAUSED);
  170.             (void) XIconifyWindow(display, mainWin, screen_num);
  171.             } else {
  172.             clearNext();
  173.             if (showNext)
  174.                 drawNext();
  175.             }
  176.             XSync(display, False);
  177.             break;
  178.  
  179.         case '\014':
  180.             XClearWindow(display, mainWin);
  181.             XClearWindow(display, blockWin);
  182.             redrawAll();
  183.             if (paused)
  184.             banner(MSG_PAUSED);
  185.             XSync(display, False);
  186.             break;
  187.  
  188.         case 'n':
  189.         case 'N':
  190.             if (!paused) {
  191.             showNext = !showNext;
  192.             if (showNext) {
  193.                 drawNext();
  194.             } else {
  195.                 clearNext();
  196.             }
  197.             XSync(display, False);
  198.             }
  199.             break;
  200.  
  201.         default:
  202.             XBell(display, 0);
  203.             XSync(display, False);
  204.             break;
  205.         }
  206.  
  207.         break;
  208.  
  209.         case UnmapNotify:
  210.         paused = True;
  211.         break;
  212.  
  213.         case FocusOut:
  214.         if (firstFall) {
  215.             paused = True;
  216.             banner(MSG_PAUSED);
  217.         }
  218.         break;
  219.  
  220.         case Expose:
  221.         if (ev.xexpose.count == 0) {
  222.             redrawAll();
  223.             if (paused)
  224.             banner(MSG_PAUSED);
  225.         }
  226.         break;
  227.  
  228.         case ClientMessage:
  229.         if ((Atom) ev.xclient.data.l[0] == delw)
  230.             gameOver();
  231.         break;
  232.  
  233.         case DestroyNotify:
  234.         exit(0);
  235.         break;
  236.         }
  237.         if (paused) {
  238.         XNextEvent(display, &ev);
  239.         flag = True;
  240.         gotNew = True;        /* for reseting time */
  241.         } else
  242.         flag = False;
  243.     }
  244.     }
  245.  
  246.     XSync(display, False);
  247.     return gotNew;
  248. }
  249.  
  250. /* ------------------------------------------------------------------ */
  251.  
  252. void
  253. redrawAll()
  254. {
  255.     drawTitle();
  256.     drawStatus();
  257.     drawField();
  258.     drawThing();
  259.     if (showNext)
  260.     drawNext();
  261. }
  262.  
  263. /* ------------------------------------------------------------------ */
  264.  
  265. Bool
  266. moveOne(move)
  267.     move_t          move;
  268. {
  269.     XEvent          ev;
  270.     int             lines;
  271.  
  272.     if ((move == DROP) || ((move == FALL) && atBottom())) {
  273.     tryMove(move);
  274.     putBox();
  275.     lines = checkLines();
  276.     score += prefilled * prefilled + lines + 1;
  277.     score += (showNext ? 3 : 5) * level * level * lines * lines;
  278.     rows += lines;
  279.     if (rows > thresh[level])
  280.         level++;
  281.     drawStatus();
  282.     newThing();
  283.     if (showNext) {
  284.         clearNext();
  285.         drawNext();
  286.     }
  287.     XSync(display, True);    /* discard all events */
  288.     if (overlapping())
  289.         gameOver();
  290.     drawThing();
  291.     return True;
  292.     } else {
  293.     tryMove(move);
  294.     if (rows > thresh[level]) {
  295.         level++;
  296.         drawStatus();
  297.     }
  298.     return False;
  299.     }
  300. }
  301.  
  302. /* ------------------------------------------------------------------ */
  303.  
  304. static void
  305. addScore()
  306. {
  307.     time_t          tloc;
  308.     char            buff[2][SCORESIZE];
  309.     char            lockfile[FILENAMELEN];
  310.     int             fd, lfd;
  311.     int             tmp, ptmp, s1;
  312.     int             mycount = 0;
  313.     Bool            saved = False, trickle = False;
  314.  
  315.     time(&tloc);
  316.     (void) strcpy(myscore.mydate, asctime(localtime(&tloc)));
  317.     (void) sprintf(myscore.score, "%9d", score);
  318.     (void) sprintf(myscore.level, "%3d", level);
  319.     (void) sprintf(myscore.rows, "%4d", rows);
  320.  
  321.     (void) fprintf(stderr, "\n- %s", myscore.mydate);
  322.     (void) fprintf(stderr, "- Your final score is %d,", score);
  323.     (void) fprintf(stderr, " at level %d with %d rows.\n\n", level, rows);
  324.  
  325.     if ((fd = open(SCOREFILE, O_CREAT | O_RDWR, 0644)) < 0) {
  326.     (void) fprintf(stderr, "Cannot write the score-file!\n");
  327.     return;
  328.     }
  329.     /* lock */
  330.     (void) strcpy(lockfile, SCOREFILE);
  331.     (void) strcat(lockfile, ".lock");
  332.     while (((lfd = open(lockfile, O_CREAT | O_EXCL, 0644)) < 0) &&
  333.         errno == EEXIST)
  334.     sleep(1);
  335.  
  336.     if (lfd < 0) {
  337.     (void) perror("Error in creating the score-file lock-file");
  338.     (void) fprintf(stderr, "Score not recorded - sorry.\n");
  339.     return;
  340.     }
  341.     tmp = 0;
  342.     ptmp = 1;
  343.     bcopy((char *) &myscore, buff[1], SCORESIZE);
  344.  
  345.     while (read(fd, buff[tmp], SCORESIZE) == SCORESIZE) {
  346.     sscanf(((score_t *) buff[tmp])->score, " %d", &s1);
  347.     if (!saved && (s1 <= score)) {
  348.         trickle = True;
  349.         saved = True;
  350.         mycount++;
  351.     }
  352.     if (!strncmp(myscore.myname, ((score_t *) buff[tmp])->myname,
  353.              NAMELEN)) {
  354.         mycount++;
  355.     }
  356.     /* Then check if we should trickle the score */
  357.     if (trickle) {
  358.         lseek(fd, (off_t) - SCORESIZE, SEEK_CUR);
  359.         write(fd, buff[ptmp], SCORESIZE);
  360.         ptmp = tmp;
  361.         tmp = (tmp + 1) % 2;
  362.     }
  363.  
  364.     /*
  365.      * As we trickle, we add up records owned by me. Once we hit max, we
  366.      * throw it away, and stop trickling.
  367.      */
  368.     if ((mycount > MAXSCORES) || ((mycount == MAXSCORES) && !trickle)) {
  369.         trickle = False;
  370.         break;
  371.     }
  372.     }                /* while */
  373.  
  374.     if (trickle) {
  375.     write(fd, buff[ptmp], SCORESIZE);
  376.     }
  377.     if (!saved && (mycount < MAXSCORES)) {
  378.     write(fd, (char *) &myscore, SCORESIZE);
  379.     }
  380.     /* unlock */
  381.     close(lfd);
  382.     (void) unlink(lockfile);
  383.     close(fd);
  384. }
  385.  
  386. /* ------------------------------------------------------------------ */
  387.  
  388. void
  389. gameOver()
  390. {
  391.     banner(MSG_END);
  392.     XFlush(display);
  393.     addScore();
  394.     showScores(SHOWSCORES);
  395.     XCloseDisplay(display);
  396.     exit(0);
  397. }
  398.  
  399. /* ------------------------------------------------------------------ */
  400.  
  401. void
  402. showScores(num)
  403.     int             num;
  404. {
  405.     int             fd, i = 0;
  406.     score_t         curs;
  407.  
  408.     if ((fd = open(SCOREFILE, O_RDONLY, 0644)) < 0)
  409.     return;
  410.  
  411.     (void) fprintf(stderr, "            GENERIC TETRIS  HALL OF FAME\n\n");
  412.     (void) fprintf(stderr,
  413.         "   # USER            SCORE   L    R  HOST         DATE\n");
  414.  
  415.     while (read(fd, (char *) &curs, SCORESIZE) == SCORESIZE) {
  416.     i++;
  417.     if ((num == 0) || (i <= num))
  418.         (void) fprintf(stderr, "%4d %-12s%9s %3s %4s  %-12s %-s",
  419.                i, curs.myname, curs.score, curs.level, curs.rows,
  420.                curs.myhost, curs.mydate);
  421.     }
  422.     close(fd);
  423.     (void) fprintf(stderr, "There are %d scores to date.\n", i);
  424. }
  425.  
  426. /* ------------------------------------------------------------------ */
  427.